/**
  ******************************************************************************
  * @file    /System/bsp_init.c
  * @author  Zheyu Zhou, Zhenyu Yang, HSiang HSu. 
  * @version V0.1
  * @date    2022年12月25日 V0.1：I/O, USART, EXTI, DMA
  *          2023年11月27日 V0.2：USB, CRC, TIM
  * @brief   板级支持包驱动程序
  ******************************************************************************
**/
/* 1.Include -------------------------------------------------------------------*/
#include "bsp_init.h"
#include "tusb.h"
/* 2.Private typedef -----------------------------------------------------------*/
/* 3.Private define ------------------------------------------------------------*/
/* 4.Private macro -------------------------------------------------------------*/
/* 5.Global variables ---------------------------------------------------------*/
/* 6.Private variables ---------------------------------------------------------*/
/* 7.Global function prototypes -----------------------------------------------*/
/* 8.Private function prototypes -----------------------------------------------*/
static void GPIO_Configuration(void);
static void UART_Configuration(void);
static void TIM_Configuration(void);
static void EXTI_Configuration(void);
static void CRC_Configuration(void);
static void USBD_Configuration(void);
/* 9.functions -----------------------------------------------------------------*/

/**
* @brief  GPIO_Configuration   I/O初始化
* @param  None
* @retval None                  
*/
static void GPIO_Configuration(void)
{
    // Add your application code here 
    LL_GPIO_InitTypeDef  GPIO_InitStruct;

    // 开启IO时钟
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

    // PA5, PA7: output;
    GPIO_InitStruct.Pin       = LL_GPIO_PIN_5 | LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode      = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OutputType= LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull      = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed     = LL_GPIO_SPEED_FREQ_HIGH;
    //GPIO_InitStruct.Alternate =
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_7);

    // PA6:Input.
    GPIO_InitStruct.Pin       = LL_GPIO_PIN_6 ;
    GPIO_InitStruct.Mode      = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull      = LL_GPIO_PULL_DOWN;
    GPIO_InitStruct.Speed     = LL_GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

     // PA8 LED
    GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_8);
        
    /* Set PA11 and PA12 to AF10 (USB_FS) */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_11 | LL_GPIO_PIN_12;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 外部中断PA1
    GPIO_InitStruct.Pin       = LL_GPIO_PIN_1 ;
    GPIO_InitStruct.Mode      = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull      = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Speed     = LL_GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/**
* @brief  UART_Configuration   串口初始化
* @param  None
* @retval None                  
*/
static void UART_Configuration(void)
{
    // 结构体定义
    LL_USART_InitTypeDef USART_InitStruct;
    LL_GPIO_InitTypeDef  GPIO_InitStruct;

    // 串口1配置，用于数据传输
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);                  // GPIOA 时钟
    // IO配置PA9、PA10
    GPIO_InitStruct.Pin        = LL_GPIO_PIN_10 | LL_GPIO_PIN_9;
    GPIO_InitStruct.Mode       = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed      = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull       = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate  = LL_GPIO_AF_7;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // 串口参数配置
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);                 // USART1 时钟
    USART_InitStruct.BaudRate            = 921600;
    USART_InitStruct.DataWidth           = LL_USART_DATAWIDTH_8B;
    USART_InitStruct.StopBits            = LL_USART_STOPBITS_1;
    USART_InitStruct.Parity              = LL_USART_PARITY_NONE;
    USART_InitStruct.TransferDirection   = LL_USART_DIRECTION_TX_RX;
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    USART_InitStruct.OverSampling        = LL_USART_OVERSAMPLING_16;
    LL_USART_Init(USART1, &USART_InitStruct);
     LL_USART_ConfigAsyncMode(USART1);                                     // 异步模式
    LL_USART_EnableIT_IDLE(USART1);                                       // 串口空闲中断
    LL_USART_Enable(USART1);                                              // 使能串口
    // USART1 中断优先级
    NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),2, 0));
    NVIC_EnableIRQ(USART1_IRQn);  

    // DMA 接收初始化，DMA2通道2
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);                   // DMA2 时钟
    LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_2, LL_DMA_CHANNEL_4);
    LL_DMA_ConfigTransfer(DMA2, LL_DMA_STREAM_2, 
                        LL_DMA_DIRECTION_PERIPH_TO_MEMORY | 
                        LL_DMA_PRIORITY_HIGH              | 
                        LL_DMA_MODE_NORMAL                | 
                        LL_DMA_PERIPH_NOINCREMENT         | 
                        LL_DMA_MEMORY_INCREMENT           | 
                        LL_DMA_PDATAALIGN_BYTE            | 
                        LL_DMA_MDATAALIGN_BYTE);
    LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_2,
                            LL_USART_DMA_GetRegAddr(USART1),
                            (uint32_t)suart1.rxbuf,
                            LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_2));
    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, USART_BUF_LEN);
    // DMA 发送初始化，DMA2通道7
    LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_7, LL_DMA_CHANNEL_4);
    LL_DMA_ConfigTransfer(DMA2, LL_DMA_STREAM_7, 
                        LL_DMA_DIRECTION_MEMORY_TO_PERIPH | 
                        LL_DMA_PRIORITY_HIGH              | 
                        LL_DMA_MODE_NORMAL                | 
                        LL_DMA_PERIPH_NOINCREMENT         | 
                        LL_DMA_MEMORY_INCREMENT           | 
                        LL_DMA_PDATAALIGN_BYTE            | 
                        LL_DMA_MDATAALIGN_BYTE);
    LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_7,
                            (uint32_t)suart1.txbuf,
                            LL_USART_DMA_GetRegAddr(USART1),
                            LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_7));
    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_7, USART_BUF_LEN);           // 设置缓存大小
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_2);
    LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_2);
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_7);
    LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_7);
    // 设置DMA中断优先级
    NVIC_SetPriority(DMA2_Stream2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
    NVIC_EnableIRQ(DMA2_Stream2_IRQn);
    NVIC_SetPriority(DMA2_Stream7_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 1));
    NVIC_EnableIRQ(DMA2_Stream7_IRQn);

    /* Enable DMA RX Interrupt */
    LL_USART_EnableDMAReq_RX(USART1);

    /* Enable DMA TX Interrupt */
    LL_USART_EnableDMAReq_TX(USART1);

    /* Enable DMA Channel Rx */
    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);

    /* Enable DMA Channel Tx */
    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_7);
                               
}

/**
* @brief  TIM_Configuration    定时器初始化
* @param  None
* @retval None                  
*/
static void TIM_Configuration(void)
{

    LL_TIM_InitTypeDef TIM_InitStruct = {0};

    /* Peripheral clock enable */
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

    /* USER CODE BEGIN TIM3_Init 1 */

    /* USER CODE END TIM3_Init 1 */
    // 产生1kHz定时器中断，84MHz/(199+1)/(419+1)
    TIM_InitStruct.Prescaler = 199;
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Autoreload = 420 - 1;
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
    LL_TIM_Init(TIM3, &TIM_InitStruct);
    LL_TIM_EnableARRPreload(TIM3);
    LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
    LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_RESET);
    LL_TIM_DisableMasterSlaveMode(TIM3);
    
    // 中断设置
    NVIC_SetPriority(TIM3_IRQn,  NVIC_EncodePriority (NVIC_GetPriorityGrouping(), 1, 3));
    NVIC_EnableIRQ(TIM3_IRQn);

    // 使能定时器中断
    LL_TIM_EnableIT_UPDATE(TIM3);

    // 使能定时器计数
    LL_TIM_EnableCounter(TIM3);

    // 重载更新
    LL_TIM_GenerateEvent_UPDATE(TIM3);

}

/**
* @brief  EXTI_Configuration   外部中断初始化
* @param  None
* @retval None                  
*/
static void EXTI_Configuration(void)
{
    // Add your application code here 
    // 使能时钟
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); 

    // 1 号通道
    LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTA, LL_SYSCFG_EXTI_LINE1);
    LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_1);
    LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_1);
    NVIC_EnableIRQ(EXTI1_IRQn); 
    NVIC_SetPriority(EXTI1_IRQn, 0);

}

/*******************************************************************************
** 名    称 ： CRC_Configuration
** 功    能 ： 板级支持包初始化
** 入口参数 ： 无
** 出口参数 ： 无
*******************************************************************************/
static void CRC_Configuration(void)
{
    /* Enable peripheral clock */
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC);

    // LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_BYTE);
    // LL_CRC_SetOutputDataReverseMode(CRC, LL_CRC_OUTDATA_REVERSE_BIT);
    // LL_CRC_SetPolynomialCoef(CRC, LL_CRC_DEFAULT_CRC32_POLY);
    // LL_CRC_SetPolynomialSize(CRC, LL_CRC_POLYLENGTH_32B);
    // LL_CRC_SetInitialData(CRC, LL_CRC_DEFAULT_CRC_INITVALUE);
}

/*******************************************************************************
** 名    称 : USBD_Configuration
** 功    能 : USB 初始化
** 入口参数 : 无
** 出口参数 : 无
*******************************************************************************/
static void USBD_Configuration(void)
{

    /* Enable USB power supply */
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_OTGFS);
    LL_AHB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);

    // Enable VBUS sensing (stm32f4xx_ll_usb.c#L342)
    USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_NOVBUSSENS;
    USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN;

    /* Peripheral interrupt init */
    NVIC_SetPriority(OTG_FS_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));

    NVIC_EnableIRQ(OTG_FS_IRQn);
    tud_init(0);

}
/*******************************************************************************
** 名    称 ： BSP_Init
** 功    能 ： 板级支持包初始化
** 入口参数 ： 无
** 出口参数 ： 无
*******************************************************************************/
void BSP_Init(void)
{

    // IO功能配置
    GPIO_Configuration();
        
    // 串口配置
    UART_Configuration();    

    // USB
    USBD_Configuration();                                             

    // 外部中断配置
    EXTI_Configuration();

    // 定时器配置
    TIM_Configuration();

    // CRC
    CRC_Configuration();
    
}

/* end------------------------------------------------------------------------*/


